package com.block.product.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.block.common.constant.AppRspCodeConstant;
import com.block.common.vo.ResponseVo;
import com.block.db.entity.MemberBaseInfo;
import com.block.db.entity.ProductBaseInfo;
import com.block.db.entity.ProductUnionResultInfo;
import com.block.db.mapper.MemberBaseInfoMapper;
import com.block.db.mapper.ProductBaseInfoMapper;
import com.block.db.mapper.ProductUnionResultInfoMapper;
import com.block.product.enums.UniStatusEnum;
import com.block.product.factory.UnionLoginFactory;
import com.block.product.model.dto.UniLoginDTO;
import com.block.product.model.param.ProdApiInfoParam;
import com.block.product.model.result.UnionLoginResult;
import com.block.product.service.IProductBaseInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 产品基本信息 服务实现类
 * </p>
 *
 * @author
 * @since 2023-09-02
 */
@Service
public class ProductBaseInfoServiceImpl extends ServiceImpl<ProductBaseInfoMapper, ProductBaseInfo> implements IProductBaseInfoService {

    @Resource
    private RedisTemplate<String, ProductBaseInfo> redisProductBaseInfoTemplate;
    @Autowired
    MemberBaseInfoMapper memberBaseInfoMapper;
    @Autowired
    ProductUnionResultInfoMapper productUnionResultInfoMapper;

    private static final String PRODUCTINFO_KEY_PREFIX = "PRODUCT:BASEINFO:";
    private static final Long PRODUCTINFO_KEY_TIME_OUT = 4L;

    @Override
    public ProductBaseInfo getProductInfoById(Integer productId) {
        String redisKey = PRODUCTINFO_KEY_PREFIX + productId;
        ProductBaseInfo productBaseInfo = redisProductBaseInfoTemplate.opsForValue().get(redisKey);
        if (ObjectUtil.isEmpty(productBaseInfo)) {
            productBaseInfo = this.baseMapper.selectById(productId);
            if (productBaseInfo != null) {
                redisProductBaseInfoTemplate.opsForValue().set(redisKey, productBaseInfo, PRODUCTINFO_KEY_TIME_OUT, TimeUnit.HOURS);
            }
        }
        return productBaseInfo;
    }

    @Override
    public ResponseVo pushMerchantApis() {
        try {
            // 1. 查询十分钟前未实名的用户
            LocalDateTime tenMinutesAgo = LocalDateTime.now().minusMinutes(10);
            List<MemberBaseInfo> memberBaseInfos = memberBaseInfoMapper.getBaseUserInfoByCreateTime(tenMinutesAgo, LocalDateTime.now());

            if (memberBaseInfos == null || memberBaseInfos.isEmpty()) {
                return new ResponseVo(AppRspCodeConstant.SUCCESS, "十分钟内没有未填资用户");
            }

            // 2. 获取产品配置信息
            ProductBaseInfo productBaseInfo = this.baseMapper.selectById("113");
            if (productBaseInfo == null) {
                return new ResponseVo(AppRspCodeConstant.ACTION_ERROR, "产品配置不存在");
            }

            // 3. 构建API参数
            ProdApiInfoParam prodApiInfoParam = buildProdApiInfoParam(productBaseInfo);

            // 4. 处理每个用户
//            for (MemberBaseInfo memberBaseInfo : memberBaseInfos) {
//                processSingleUser(memberBaseInfo, productBaseInfo, prodApiInfoParam);
//            }
            processUsersParallel(memberBaseInfos, productBaseInfo, prodApiInfoParam);

            return new ResponseVo(AppRspCodeConstant.SUCCESS, String.format("成功处理 %d 个用户", memberBaseInfos.size()));

        } catch (Exception e) {
            log.error("推送商户API异常", e);
            return new ResponseVo(AppRspCodeConstant.ACTION_ERROR, "处理失败: " + e.getMessage());
        }
    }
    private void processUsersParallel(List<MemberBaseInfo> memberBaseInfos,
                                      ProductBaseInfo productBaseInfo,
                                      ProdApiInfoParam prodApiInfoParam) {
        memberBaseInfos.parallelStream().forEach(memberBaseInfo -> {
            processSingleUser(memberBaseInfo, productBaseInfo, prodApiInfoParam);
        });
    }

    private ProdApiInfoParam buildProdApiInfoParam(ProductBaseInfo productBaseInfo) {
        ProdApiInfoParam param = new ProdApiInfoParam();
        param.setFactoryType(productBaseInfo.getFactoryType());
        param.setApiSecret(productBaseInfo.getApiSecret());
        param.setCheckUrl(productBaseInfo.getCheckUrl());
        param.setLoginUrl(productBaseInfo.getLoginUrl());
        param.setApiCode(productBaseInfo.getApiCode());
        return param;
    }

    private void processSingleUser(MemberBaseInfo memberBaseInfo, ProductBaseInfo productBaseInfo, ProdApiInfoParam prodApiInfoParam) {
        try {

            ProductUnionResultInfo resultInfo = initProductUnionResultInfo(memberBaseInfo, productBaseInfo);
            productUnionResultInfoMapper.insert(resultInfo);

            UnionLoginResult checkResult = performUserCheck(memberBaseInfo, productBaseInfo, prodApiInfoParam);
            updateResultInfo(resultInfo, checkResult);

            if (checkResult.isSuccess()) {
                resultInfo.setStatus(UniStatusEnum.WAIT_LOGIN.getValue());
                productUnionResultInfoMapper.updateById(resultInfo);
                UnionLoginResult loginResult = performUserLogin(memberBaseInfo, productBaseInfo, prodApiInfoParam, checkResult.getResultInfo());
                if (loginResult.isSuccess()) {
                    updateResultInfo(resultInfo, loginResult);
                    resultInfo.setStatus(UniStatusEnum.SUCCESS.getValue());
                } else {
                    resultInfo.setStatus(UniStatusEnum.MATCH_FAILD.getValue());
                }
                productUnionResultInfoMapper.updateById(resultInfo);
            } else {
                resultInfo.setStatus(UniStatusEnum.MATCH_FAILD.getValue());
                productUnionResultInfoMapper.updateById(resultInfo);
            }

        } catch (Exception e) {
            log.error("处理用户 {} 异常", e);
        }
    }
    
    private ProductUnionResultInfo initProductUnionResultInfo(MemberBaseInfo memberBaseInfo, ProductBaseInfo productBaseInfo) {
        ProductUnionResultInfo resultInfo = new ProductUnionResultInfo();
        resultInfo.setProductId(productBaseInfo.getId());
        resultInfo.setProductName(productBaseInfo.getProductName());
        resultInfo.setDateInfo(LocalDate.now().toString());
        resultInfo.setUid(memberBaseInfo.getUid());
        resultInfo.setMobile(memberBaseInfo.getMobile());
        resultInfo.setStatus(UniStatusEnum.INIT.getValue());
        resultInfo.setChannelCode(memberBaseInfo.getChannelCode());
        resultInfo.setChannelName(memberBaseInfo.getChannelName());
        return resultInfo;
    }

    private UnionLoginResult performUserCheck(MemberBaseInfo memberBaseInfo, ProductBaseInfo productBaseInfo, ProdApiInfoParam prodApiInfoParam) throws Exception {
        UniLoginDTO uniLoginDTO = new UniLoginDTO();
        uniLoginDTO.setMobile(memberBaseInfo.getMobile());
        return UnionLoginFactory.getService(productBaseInfo.getFactoryType())
                .checkUser(uniLoginDTO, prodApiInfoParam);
    }


    private UnionLoginResult performUserLogin(MemberBaseInfo memberBaseInfo, ProductBaseInfo productBaseInfo,
                                              ProdApiInfoParam prodApiInfoParam, String resultInfo) throws Exception {
        UniLoginDTO uniLoginDTO = new UniLoginDTO();
        uniLoginDTO.setMobile(memberBaseInfo.getMobile());
        return UnionLoginFactory.getService(productBaseInfo.getFactoryType())
                .loginUser(uniLoginDTO, prodApiInfoParam, resultInfo);
    }


    private void updateResultInfo(ProductUnionResultInfo resultInfo, UnionLoginResult unionResult) {
        resultInfo.setCode(unionResult.getCode());
        resultInfo.setMessage(unionResult.getMessage());
        resultInfo.setResultInfo(unionResult.getResultInfo());
        resultInfo.setParamInfo(unionResult.getParamInfo());
    }


}
